﻿using System;
using System.Reflection;
using System.Runtime.InteropServices.Expando;
using System.Runtime.InteropServices.ComTypes;
using System.ComponentModel;
using System.ComponentModel.Design;
using System.Drawing;
using System.Drawing.Imaging;
using System.Threading;
using System.Collections;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using System.Net;
using System.Linq;
using System.Text;
using BrainTechLLC;
using System.Configuration;
using System.Diagnostics;
using BrainTechLLC.ThreadSafeObjects;

namespace BrainTechLLC.ImageOperatorsNonAForgeDependent
{   
    public static class CreateBitmapFromFrameInfo
    {
        [DllImport("ntdll.dll")]
        private static unsafe extern byte* memcpy(
            byte* dst,
            byte* src,
            int count);

        public static unsafe Bitmap CreateBitmap(this FrameInfo frameInfo)
        {
            if (frameInfo._bytes == null)
                return null;

            fixed (void* p = &(frameInfo._bytes[0]))
            {
                IntPtr ptr = new IntPtr(p);
                Bitmap bm = new Bitmap(frameInfo.Width, frameInfo.Height, frameInfo.StrideGuess, frameInfo.PixelFormat, ptr);
                return bm;
            }
        }

        public static unsafe byte[] CreateBytes(this Bitmap bm)
        {
            // both widths?
            int nStrideGuess = (bm.Width * 3) + ((bm.Width * 3) % 4);
            int imageSize = (nStrideGuess * bm.Height);
            byte[] newBytes = new byte[imageSize];

            BitmapData bmData = bm.LockBits(new Rectangle(0, 0, bm.Width, bm.Height), ImageLockMode.ReadWrite, bm.PixelFormat);
            try
            {
                unsafe
                {
                    fixed (byte* pb = &(newBytes[0]))
                    {
                        memcpy(pb, (byte*)bmData.Scan0.ToPointer(), imageSize);
                    }
                }
            }
            finally
            {
                bm.UnlockBits(bmData);
            }

            return newBytes;
        }
    }

    public class FrameInfo
    {
        public Bitmap _bitmap;
        public byte[] _bytes;
        public byte[] Bytes { get { return _bytes; } set { _bytes = value; } }
        public PixelFormat PixelFormat { get; set; }
        public object _lockObject;        
        public int StrideGuess { get; set; }
        public int Width { get; set; }
        public int Height { get; set; }
        public string CameraName { get; set; }
        public string CameraMoniker { get; set; }
        public double ImageFrameTime { get; set; }
        public int ByteLength { get; set; }

        public Bitmap Bitmap
        {
            get
            {
                if (_bitmap == null)
                {
                    if (_lockObject == null)
                    {
                        Interlocked.CompareExchange<object>(ref _lockObject, new object(), null);
                    }

                    lock (_lockObject)
                    {
                        if (_bitmap == null)
                        {
                            _bitmap = this.CreateBitmap();
                        }
                    }
                }

                return _bitmap;
            }
            set
            {
                if (_bitmap != value)
                {
                    _bitmap = value;
                }
            }
        }

        public void ClearBitmapAndBytes()
        {            
            _bitmap = null;
            _bytes = null;
        }
    }
}
